import { DbService } from '@app/db';
import { Body, Controller, Delete, Get, Param, ParseIntPipe, Post, Put, Query, Req } from '@nestjs/common';
import { BaseController } from '../base/base.controller';
import { DtoPipe } from '../pipes/dto/dto.pipe';
import { AddBatchDto, AddDto, EditDto, PageDto } from './dto';
import { IotSim } from '@app/db/entities/IotSim';
import { FindOptionsWhere, In, JsonContains, Like } from 'typeorm';
import * as dayjs from 'dayjs';
import { CacheService } from '@app/cache';
import { Device } from '@app/db/entities/Device';

@Controller('iotSim')
export class IotSimController extends BaseController{
    constructor(
        private readonly db:DbService,
        private readonly cache:CacheService
    ){
        super()
    }

    @Get('query')
    async query(@Query() querys : {id:string, cardNo:string}) {
        let where:FindOptionsWhere<IotSim> = {}
        if(querys.id) {
            let id = Number(querys.id)
            if(Number.isInteger(id) && id > 0) {
                where.id = id
            }
        }else if(querys.cardNo) {
            where.cardNo = Like('%' + querys.cardNo + '%')
        }else {
            return this.failRes()
        }

    
    

        const cards = await this.db.iotSim.find(where, {cardNo : true, id : true}, 0, 10)


        return this.successRes(cards)

    }

    @Get('page')
    async rolePage(@Query() dto:PageDto) {
        let result:PaginationResult<IotSim> = {
            total : 0,
            rows : []
        }

        let where:FindOptionsWhere<IotSim> = {
            
        }

        if(dto.cardNo) {
            where.cardNo = dto.cardNo
        }

        result.total = await this.db.iotSim.count(where)

        if(result.total > 0) {
            result.rows = await this.db.iotSim.pagination(dto.pageNo, dto.pageSize, where, null, {id : 'DESC'})
        }
        

        return this.successRes(result)

    }

    @Post('add')
    async add(@Body(new DtoPipe({skipMissingProperties : false})) dto:AddDto, @Req() { locale }) {
        const lockKey = 'add:sim'
        const lock = await this.cache.blockLock(lockKey, 10)
        if(!lock) return this.failRes()

        if(true == await this.db.iotSim.isExistsByWhere({cardNo : dto.cardNo})) {
            this.cache.unBlockLock(lockKey)
            return this.failRes(this.i18n.t(locale, 'cardNoIsExists'))
        }

        const data:KeyToValueType<IotSim> = {
            createTime : this.utils.time(),
            cardNo : dto.cardNo
        }

        if(dto.fee) {
            data.fee = dto.fee
        }

        if(dto.expireIn) {
            data.expireIn = data.expireIn
        }

        const res = await this.db.iotSim.insert(data)
        this.cache.unBlockLock(lockKey)
        return res ? this.successRes() : this.failRes()
    }

    @Post('add/batch')
    async addBatch(@Body(new DtoPipe({skipMissingProperties : false})) dto:AddBatchDto, @Req() { locale }) {
        const lockKey = 'add:sim'
        const lock = await this.cache.blockLock(lockKey, 10)
        if(!lock) return this.failRes()

        const cardNos = dto.data.map(item =>  item.cardNo)
        const cards = await this.db.iotSim.find({cardNo : In(cardNos)}, ['cardNo'])
        if(cards.length > 0) {
            this.cache.unBlockLock(lockKey)
            return this.failRes(this.i18n.t(locale, 'cardNoIsExists'), {code : 300, data : cards})
        }

        const res = await this.db.iotSim.insert(dto.data)
        this.cache.unBlockLock(lockKey)
        return res ? this.successRes() : this.failRes()
    }


    @Put('edit/:id')
    async edit(@Body(new DtoPipe()) dto:EditDto, @Param('id', ParseIntPipe) id:number, @Req() { locale }) {
        if(id <= 0) return
        

        let fields = Object.keys(dto) as (keyof IotSim)[]
        if(fields.length == 0) return

        const sim = await this.db.iotSim.findOne({ id }, fields)
        
        if(!sim) return

        let updateData:KeyToValueType<IotSim> = {}


        for(let k in sim) {
            if(sim[k] != dto[k]) {
                updateData[k] = dto[k]
            }
        }

        if(Object.keys(updateData).length == 0) return this.successRes()

        let lockKey = ''
        if(updateData.cardNo) {
            lockKey = 'add:sim'
            const lock = await this.cache.blockLock(lockKey, 10)
            if(!lock) return this.failRes()
            if(true == await this.db.iotSim.isExistsByWhere({cardNo : updateData.cardNo})) {
                this.cache.unBlockLock(lockKey)
                return this.failRes(this.i18n.t(locale, 'cardNoIsExists'))
            }
            
        }

        const res = await this.db.iotSim.update({id : id}, updateData)
        if(lockKey !== '') {
            this.cache.unBlockLock(lockKey)
        }
        return res === 0 ? this.failRes() : this.successRes()
    }


    @Delete('delete/:id')
    async delete(@Param('id', ParseIntPipe) id:number) {
        if(id <= 0) return
        const res = await this.db.iotSim.delete({id : id})
        return res === 0 ? this.failRes() : this.successRes()
    }

}
